/* eslint-disable @typescript-eslint/no-use-before-define */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-nested-ternary */
import type { FieldNames, NamePath, PathSegment } from '..';
import { ChildrenKey, ComponetCls, DefaultTreeValue, RelationKey } from './constant';

export function uuid() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

export function getDeepth(path: PathSegment[]) {
  return Math.ceil(path.length / 2);
}

/** 规一化路径 */
export function normalizePath(path: string | number | NamePath | undefined) {
  if (Array.isArray(path)) {
    return path;
  }
  if (path === undefined) {
    return [];
  }
  return [path];
}

/** 规一化gap */
export function normalizeGap(gap: number | [number, number] | undefined): [number, number] {
  return gap ? (Array.isArray(gap) ? gap : [gap, gap]) : [32, 16];
}


/** 填充字段名称默认值 */
export function fillFieldNames(fieldNames?: FieldNames): Required<FieldNames> {
  const { relation, children } = fieldNames || {};
  return {
    relation: relation || RelationKey,
    children: children || ChildrenKey,
  };
}


export function getRelationPath(path: PathSegment[], relationKey = RelationKey) {
  if (!path.length) {
    console.error('path is not valid');
    return [];
  }

  const newPath = [...path];
  newPath[newPath.length - 1] = relationKey;
  return newPath;
}

/** 把namePath转换成levelPath */
export function toLevelPath(path: PathSegment[]) {
  return path.filter(p => typeof p === 'number') as number[];
}

/** 把levelPath转换成namePath */
export function toNamePath(levelPath: number[], childrenKey = ChildrenKey): PathSegment[] {
  return [childrenKey, ...levelPath.map(p => [p, childrenKey]).flat(1)];
}

/** 把levelPath转换成basePath */
export function toBasePath(levelPath: number[], childrenKey = ChildrenKey): PathSegment[] {
  const namePath = toNamePath(levelPath, childrenKey);
  namePath.pop();
  return namePath;
}

/** 整理数据 */
export function normalizeValue(data: any) {
  if (data === null || data === undefined) {
    return DefaultTreeValue;
  }

  if (
    typeof data !== 'object' ||
    !(RelationKey in data && ChildrenKey in data)
  ) {
    throw new Error('RuleTree invalid value, the format like { relation: "", children: [] }');
  }

  return data;
}

/** 空操作 */
export function noop(...args: any[]): any {
  // do nothing
}

/** 合并类名 */
export function clsx(...args: any[]): string {
  return args
    .map((arg) => {
      if (typeof arg === 'string') {
        return arg;
      } else if (typeof arg === 'object' && arg !== null) {
        return Object.entries(arg)
          .filter(([_, value]) => value)
          .map(([key, _]) => key)
          .join(' ');
      }
      return '';
    })
    .filter(Boolean)
    .join(' ');
}

export function wrapperCls(prefixCls?: string) {
  if (prefixCls) {
    return `${prefixCls}-${ComponetCls}`;
  }
  return ComponetCls;
}

/** 浅拷贝 */
export function shallowClone<T>(obj: T) {
  if (obj) {
    return Array.isArray(obj) ? [...obj] : { ...obj };
  }
  return obj;
}

/** 把合法的path string 转换成数据 */
export function normalPathStr(pathStr: string | NamePath): NamePath {
  if (Array.isArray(pathStr)) {
    return pathStr;
  }

  return pathStr.split(/[.[\]]/g).filter(p => !!p.trim()).map(p => {
    if (typeof p === 'string') {
      return p.replace(/['"]/g, '');
    }
    return p;
  });
}

/** 解析path */
export function parsePath(path: NamePath): {
  prefixName: NamePath
  name: PathSegment
} {
  const clonePath = [...path];
  const name = clonePath.pop()!;
  return {
    prefixName: clonePath,
    name,
  };
}
/**
 * 过滤object值为undefined的属性
 */
export function omitUndefined<T extends object>(obj: T) {
    return omitWith(obj, (prop) => prop === undefined);
  }
  
  export function omit<T extends object>(obj: T, keys: (keyof T)[]) {
    return omitWith(obj, (prop) => keys.includes(prop));
  }
  
  /**
   * 过滤指定属性
   */
  export function omitWith<T extends object>(
    obj: T,
    predicate: (prop: keyof T) => boolean,
  ): Partial<T> {
    return Object.keys(obj)
      .filter((k) => !predicate(k as any))
      .reduce((acc, k) => {
        acc[k] = obj[k as keyof T];
        return acc;
      }, {} as any);
  }
  
  /**
   * 拷贝的https://github.com/rayepps/radash
   */
  export const get = <T = unknown>(
    value: any,
    path: string | (string | number)[],
    defaultValue?: T,
  ): T => {
    const segments = Array.isArray(path) ? path : path.split(/[.[\]]/g).filter(x => !!x.trim());
    let current: any = value;
    for (const key of segments) {
      if (current === null) return defaultValue as T;
      if (current === undefined) return defaultValue as T;
      const dequoted = (key + '').replace(/['"]/g, '');
      if (dequoted.trim() === '') continue;
      current = current[dequoted];
    }
    if (current === undefined) return defaultValue as T;
    return current;
  };
  
  /**
   * 拷贝的https://github.com/rayepps/radash
   */
  export const toInt = <T extends number | null = number>(
    value: any,
    defaultValue?: T,
  ): number | T => {
    const def = defaultValue === undefined ? 0 : defaultValue;
    if (value === null || value === undefined) {
      return def;
    }
    const result = parseInt(value);
    return isNaN(result) ? def : result;
  };
  
  /**
   * 拷贝的https://github.com/rayepps/radash
   */
  export const set = <T extends object, K>(
    initial: T,
    path: string | (string | number)[],
    value: K,
  ): T => {
    if (!initial) return {} as T;
    if (!path || value === undefined) return initial;
    const segments = Array.isArray(path) ? path : path.split(/[.[\]]/g).filter(x => !!x.trim());
    const _set = (node: any) => {
      if (segments.length > 1) {
        const key = segments.shift() as string;
        const nextIsNum = toInt(segments[0], null) !== null;
        node[key] = node[key] === undefined ? (nextIsNum ? [] : {}) : node[key];
        _set(node[key]);
      } else {
        node[segments[0]] = value;
      }
    };
    const cloned = { ...initial };
    _set(cloned);
    return cloned;
  };
  
  /** 调用函数获取该函数的值 */
  export function invokeFunc<T extends(...args: any[]) => any>(fn: T): ReturnType<T> {
    return fn.call(null);
  }
  
  /** immutable 不可变数据，仅拷贝路径上的数据，保证更高效的更新数据 */
  export function patchUpdate(state: any, path: NamePath, updater: (state: any) => any): any {
    if (!path.length) {
      return updater(state);
    }
  
    const key = path[0];
    const nextState = Array.isArray(state) ? [...state] : { ...state };
    nextState[key] = patchUpdate(nextState[key], path.slice(1), updater);
  
    return nextState;
  }
  
  /**
   * 比较两个对象是否浅相等，支持指定属性深度比较
   * @param needDeepEqualKeys 指定深度比较的属性
   */
  export function shallow<T>(objA: T, objB: T, needDeepEqualKeys: (keyof T)[] = []): boolean {
    if (Object.is(objA, objB)) {
      return true;
    }
    if (
      typeof objA !== 'object' ||
      objA === null ||
      typeof objB !== 'object' ||
      objB === null
    ) {
      return false;
    }
  
    if (objA instanceof Map && objB instanceof Map) {
      if (objA.size !== objB.size) return false;
  
      for (const [key, value] of objA) {
        if (!Object.is(value, objB.get(key))) {
          return false;
        }
      }
      return true;
    }
  
    if (objA instanceof Set && objB instanceof Set) {
      if (objA.size !== objB.size) return false;
  
      for (const value of objA) {
        if (!objB.has(value)) {
          return false;
        }
      }
      return true;
    }  const keysA = Object.keys(objA);
    if (keysA.length !== Object.keys(objB).length) {
      return false;
    }
    for (const keyA of keysA) {
      if (needDeepEqualKeys.includes(keyA as keyof T)) {
        return shallow(objA[keyA as keyof T] as any, objB[keyA as keyof T] as any, needDeepEqualKeys);
      }
      if (
        !Object.prototype.hasOwnProperty.call(objB, keyA as string) ||
        !Object.is(objA[keyA as keyof T], objB[keyA as keyof T])
      ) {
        return false;
      }
    }
    return true;
  }
  
  /**
   * 比较两个对象是否浅相等，忽略childrenKey的比较
   */
  export function shouldUpdate(objA: any, objB: any, childrenKey: string) {
    const keysA = Object.keys(objA);
    if (keysA.length !== Object.keys(objB).length) {
      return true;
    }
  
    for (const keyA of keysA) {
      // 忽略childrenKey的比较，只比较同层
      if (keyA === childrenKey) {
        continue;
      }
  
      if (
        !Object.prototype.hasOwnProperty.call(objB, keyA as string) ||
        !Object.is(objA[keyA], objB[keyA])
      ) {
        return true;
      }
    }
  
    return false;
  }